package risoe.syslab.fhnew.hw.enocean3;

/*
 * Copyright (c) 2012-2014, Technical University of Denmark (DTU)
 * All rights reserved.
 * 
 * The Flexhouse 2.0 platform ("this software") is licensed under the
 * BSD 3-clause license.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of DTU nor the names of its contributors may be used to
 *     endorse or promote products derived from this software without specific
 *     prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE TECHNICAL UNIVERSITY OF DENMARK BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * Code courtesy of IoTSyS
 * https://code.google.com/p/iotsys/
 * @TODO Put proper copyright header here
 */

public class ESP3Frame {
	public enum STATES {
		GET_SYNC_STATE(0x01), 
		GET_HEADER_STATE(0x02), 
		CHECK_CRC8H_STATE(0x03), 
		GET_DATA_STATE(0x04), 
		CHECK_CRC8D_STATE(0x05);

		private int state;

		private STATES(int state) {
			this.state = state;
		}

		public int getState() {
			return this.state;
		}
	}

	private byte[] packetData;
	private int packetLength;
	private ESP3PacketHeader header;
	private ESP3Packet packet;

	public ESP3Frame(byte[] packetData, int packetLength) {
		this.packetData = packetData;
		this.packetLength = packetLength;
	}

	public byte[] getPacketData() {
		return packetData;
	}

	public int getPacketLength() {
		return packetLength;
	}

	public void readPacket() {
		STATES state = STATES.GET_SYNC_STATE;
		byte[] tempHeaderBuffer = new byte[ESP3PacketHeader.ESP3_HEADER_SIZE];
		byte[] tempDataBuffer = null;
		int headerCnt = 0;
		int dataCnt = 0;

		for (int i = 0; i < packetLength; i++) {
			byte tempData = packetData[i];

			switch (state) {
			case GET_SYNC_STATE:
				if (tempData == ESP3PacketHeader.ESP3_SYNC) {
					state = STATES.GET_HEADER_STATE;
					headerCnt = 0;
					dataCnt = 0;
					tempDataBuffer = null;
				} else {
					System.out.println("Enocean3: Error! - Sync byte not found!");
				}
				break;

			case GET_HEADER_STATE:
				tempHeaderBuffer[headerCnt++] = tempData;

				if (headerCnt == ESP3PacketHeader.ESP3_HEADER_SIZE) {
					state = STATES.CHECK_CRC8H_STATE;
				}
				break;

			case CHECK_CRC8H_STATE:
				if (ESP3PacketHeader.checkCRC8(tempHeaderBuffer, tempData)) {
					header = new ESP3PacketHeader(tempHeaderBuffer);
					state = STATES.GET_DATA_STATE;
				} else {
					System.out.println("Enocean3: Error! - Wrong CRC8H: "
							+ Integer.toHexString(tempData & 0xFF));
					state = STATES.GET_SYNC_STATE;
				}
				break;

			case GET_DATA_STATE:
				if (tempDataBuffer == null)
					tempDataBuffer = new byte[header.getDataLength()
					                          + header.getOptionalDataLength()];

				tempDataBuffer[dataCnt++] = tempData;
				if (dataCnt == (header.getDataLength() + header
						.getOptionalDataLength())) {
					state = STATES.CHECK_CRC8D_STATE;
				}
				break;

			case CHECK_CRC8D_STATE:
				state = STATES.GET_SYNC_STATE;

				if (ESP3PacketHeader.checkCRC8(tempDataBuffer, tempData)) {
					packet = new ESP3Packet(header, tempDataBuffer);
//					System.out.println(packet.getHeader().toString());
//					System.out.println("telegram rorg: "
//							+ packet.telegram.getRORG());
//					System.out.println("telegram senderid: "
//							+ packet.telegram.getSenderID().toString());
//					System.out.println("telegram status: "
//							+ Integer.toHexString((packet.telegram
//									.getStatusByte() & 0xFF)));
//					System.out.println("telegram payload: "
//							+ packet.telegram.getPayloadAsString());
//					System.out.println("");
				} else {
					System.out.println("Enocean3: Error! - Wrong CRC8D: "
							+ Integer.toHexString(tempData & 0xFF));
				}
				break;

			default:
				state = STATES.GET_SYNC_STATE;
				break;

			}

		}
	}

	public ESP3Packet getPacket() {
		return packet;
	}

	public ESP3PacketHeader getPacketHeader() {
		return header;
	}

}
